#include <zconf.h>
#include "Tunnel.h"

namespace zg_util{
    Tunnel* Tunnel::Add(Tunnel *next) {
        _nexts.push_back(next);
        return this;
    }

    Tunnel* Tunnel::Link(Tunnel *next) {
        _nexts.push_back(next);
        return next;
    }
    void Tunnel::Start() {
        printf("%s start\n",GetTunnelName().c_str());
        if(is_start){
            std::cout<<"current tunnel has started!"<<std::endl;
            return;
        }
        is_start=true;
        if(_nexts.size()!=0){
            for(std::vector<Tunnel*>::iterator it=_nexts.begin();it!=_nexts.end();it++){
                (*it)->Start();
            }
        }
        auto f=std::bind(&Tunnel::safe_run,this);
        _td=thread(f);
    }

    void Tunnel::Stop() {
        while(_queue.size()){
            sleep(1);
        }
        is_start= false;
        _stop_ev.wait();
        if(_nexts.size()!=0){
            for(std::vector<Tunnel*>::iterator it=_nexts.begin();it!=_nexts.end();it++){
                (*it)->Stop();
            }
        }
    }

    void Tunnel::safe_run() {
        begin:
        try {
            handler();
        }catch (std::string &exc){
            TunnelLog(exc);
            goto begin;
        }catch (...){
            TunnelLog("catch signal");
            goto begin;
        }
        _stop_ev.set();
    }

    void Tunnel::TunnelLog(const std::string info) {
        std::string temp=_tunnel_name==""?"tunnel":_tunnel_name;
        temp.append(".log");
        std::string logfile="./";
        logfile.append(temp);
        std::ofstream ofs(logfile.c_str());
        if(!ofs.is_open()){
            printf("create %s error\n",logfile.c_str());
            return;
        }
        ofs.write(info.c_str(),info.size());
        ofs.close();
    }

    void TunnelExtend::Start() {
        if(is_start){
            std::cout<<"current tunnel has started!"<<std::endl;
            return;
        }
        is_start=true;
        if(NextTunnels().size()!=0){
            for(std::vector<Tunnel*>::const_iterator it=NextTunnels().cbegin();it!=NextTunnels().cend();it++){
                (*it)->Start();
            }
        }
        for(auto i=0;i<_td_count;i++){
            _evs.push_back(Event());
            auto f=std::bind(&TunnelExtend::safe_run,this,&_evs[i]);
            _tds.push_back(thread(f));
        }
    }
    void TunnelExtend::safe_run(Event *ev) {
        begin:
        try {
            handler();
        }catch (std::string &exc){
            TunnelLog(exc);
            goto begin;
        }catch (...){
            TunnelLog("catch signal");
            goto begin;
        }
        ev->set();
    }

    void TunnelExtend::Stop() {
        while(_queue.size()){
            sleep(1);
        }
        is_start= false;
        for(auto &ev:_evs){
            ev.wait();
        }
        if(NextTunnels().size()!=0){
            for(std::vector<Tunnel*>::const_iterator it=NextTunnels().cbegin();it!=NextTunnels().cend();it++){
                (*it)->Stop();
            }
        }
    }
}